/*
 * graph2D
 * Copyright (c) 2009 Shun Moriya <shun@mnu.sakura.ne.jp>
 *
 * The MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "button.h"
#include "component.h"
#include "desktop.h"
#include "dialog.h"
#include "graphicDevice.h"
#include "layout.h"
#include "menu.h"
#include "message.h"
#include "messageWindow.h"
#include "scene.h"
#include "text.h"
#include "textWindow.h"
#include "variableContainer.h"
#include "window.h"
#include <float.h>
#include <math.h>
#include <stdlib.h>

#define COMPONENT_DISABLE_COLOR_LEVEL	(0.58f)

#if !defined(M_PI)
#define M_PI 3.14159265358979323846f
#endif

namespace Graph2D
{
	std::map<unsigned int, Component*> Component::components;
	std::stack<Component*> Component::mouseCaptureComponent;
	Component* Component::lastFoundComponent = NULL;
	unsigned int Component::lastTouchedComponentID = 0;
	bool Component::drawDebugInfomation = false;
	bool Component::dragging;

	Component::Component()
		: frameStyle(FRAME_STYLE_NOLINE|FRAME_STYLE_FLAT)
		, parent(NULL)
		, actionEvent(NULL)
		, enableColor(M_PI / 2)
	{
		setType(TYPE_COMPONENT);

		setBlendMode(GraphicDevice::BLEND_MODE_NORMAL);

		textureScrollOffset.zero();
		textureScrollSpeed.zero();

		setScale(1.0f, 1.0f, 0.0f);

		// TODO
		//clearCellAnimation();

		// コンポーネントリストに追加
		components.insert(std::pair<unsigned int, Component*>(getID(), this));
	}

	Component::~Component()
	{
		// コンポーネントリストから解放
		removeFromComponents();

#if 0
		// アニメーションリストを開放
		for(std::map<std::string, CellAnimation*>::iterator i = animations.begin(); i != animations.end(); i++)
		{
			i->second->release();
		}
#endif
		animations.clear();

		// テクスチャーを開放
		unloadTexture();
	}

	void Component::removeFromComponents()
	{
		// マウスキャプチャーコンポーネントを消去
		if(isMouseCaptured())
		{
			mouseCaptureComponent.pop();
		}

		// 最後に検索したコンポーネントを消去
		if(lastFoundComponent && lastFoundComponent->getID() == getID())
		{
			//lastFoundComponent->release();
			lastFoundComponent = NULL;
		}

		// コンポーネントリストから削除
		std::map<unsigned int, Component*>::iterator i = components.find(getID());
		if(i != components.end())
		{
			components.erase(i);
		}
	}

	/*!
	 * 親からの登録を削除します
	 */
	void Component::removeFromParent()
	{
		if(parent)
		{
			parent->remove(this);
			parent = NULL;
		}
	}

	Scene* Component::getParentScene() const
	{
		Component* component = getParent();
		while(component)
		{
			if(component->isKindOfA(TYPE_SCENE))
				break;
			component = component->getParent();
		}
		return static_cast<Scene*>(component);
	}

	void Component::applyLayout(Layout* layout)
	{
		if(layout)
		{
			layout->apply(this);
		}
	}

	/*
	 * スクロール可能なコンテナにタッチ開始イベントを発行します
	 * @param[in]	localPosition	ローカル座標
	 * @return		開始したコンテナオブジェクトポインター
	 */
	Container* Component::forcusScrollableContainer(const Vector2& localPosition)
	{
		// 自分自身を確認
		if(isKindOfA(TYPE_CONTAINER))
		{
			Container* container = static_cast<Container*>(this);
			if(container->getScrollable())
			{
				if(container->isInPosition(localPosition))
				{
					onTouchesCancelled(localPosition);
					onTouchesBegan(localPosition);
					return container;
				}
			}
		}

		// 親を再帰しながら確認
		Vector2 currentPosition = getPosition() + localPosition;
		for(Container* container = getParent(); container; container = container->getParent())
		{
 			if(container->getScrollable())
			{
				if(container->isInPosition(currentPosition))
				{
					onTouchesCancelled(localPosition);
					container->onTouchesBegan(currentPosition);
					return container;
				}
			}
			// 親の座標系に変換
			currentPosition += container->getPosition();
		}

		// 発見できず
		return NULL;
	}

	/*
	 * スクロール可能なコンテナを取得します
	 * @return	開始したコンテナオブジェクトポインター
	 */
	Container* Component::getScrollableContainer()
	{
		for(Container* container = getParent(); container; container = container->getParent())
		{
			if(container->getScrollableContainer())
				return container;
		}

		// 発見できず
		return NULL;
	}

	/*
	 * スクリーン座標を取得します
	 * @return	スクリーン座標
	 */
	Vector2 Component::getScreenPosition() const
	{
		Vector2 position;

		for(const Component* component = this; component; component = component->getParent())
		{
			position += component->getLeftTopPosition();
		}

		return position;
	}

	/*
	 * スクリーン座標をローカル座標に変換します
	 * @param[in]	screenPosition	スクリーン座標
	 * @return		ローカル座標
	 */
	Vector2 Component::translatePosition(const Vector2& screenPosition) const
	{
		Vector2 position = screenPosition;

		for(const Component* component = this; component; component = component->getParent())
		{
			position -= component->getPosition();
		}

		return position;
	}

#if 0
	Vector2 Component::getBottomPosition() const
	{
		Vector2 bottomPosition;
		bottomPosition = getCenterPosition();
		bottomPosition.y += getSize().y * getScale().y;

		if(jumpTime > 0.0f)
		{
			bottomPosition.y += jumpHeight * sinf(jumpTime * jumpAngle);
		}

		return bottomPosition;
	}
#endif

	//! サイズを設定します
	void Component::setSize(const Vector2& size)
	{
		// イベント呼び出し
		if(onSize(size))
		{
			// サイズ設定
			super::setSize(size);
			// イベント呼び出し
			onSizeChanged();
		}
	}

	void Component::setSize(const float w, const float h)		//!< サイズを設定します
	{
		setSize(Vector2(w, h));
	}




#if 0
	// TODO

	void Component::setCellAnimation(const Vector2& position, const Vector2& size, const float wait, const unsigned short count, const short loopCount)
	{
		animationCellStartPosition = position;
		animationCellSize = size;
		animationCellTime = 0;
		animationCellWait = wait;
		animationCellCount = 0;
		animationCellMaxCount = count;
		animationCellLoopCountOrigin = loopCount;
		animationCellLoopCount = loopCount;
		animationCellEnable = true;
		animationCellRunning = false;
	}

	float Component::getCellAnimationTime() const
	{
		// 無限ループ？
		if(animationCellLoopCount < 0)
			return FLT_MAX;
		// セルアニメーションの時間を計算
		return animationCellWait * animationCellMaxCount * (animationCellLoopCount + 1);
	}

	void Component::setCell(const Vector2& position, const Vector2& size)
	{
		setCellAnimation(position, size, FLT_MAX, 1, -1);
	}

	void Component::removeAnimation(const std::string& name)
	{
		std::map<std::string, CellAnimation*>::iterator i = animations.find(name);
		if(i != animations.end())
		{
			i->second->release();

			animations.erase(i);
		}
	}

	bool Component::setAnimation(const std::string& name)
	{
		std::map<std::string, CellAnimation*>::iterator i = animations.find(name);
		if(i == animations.end())
		{
			return false;
		}
		else
		{
			CellAnimation* animation = i->second;
			setCellAnimation(animation->getPosition(), animation->getSize(), animation->getWait(), animation->getCount(), animation->getLoop());
			startCellAnimation();
			return true;
		}
	}

	CellAnimation* Component::getAnimation(const std::string& name)
	{
		const std::map<std::string, CellAnimation*>::iterator i = animations.find(name);
		if(i != animations.end())
		{
			return i->second;
		}else{
			return NULL;
		}
	}

#endif

	//! マウスキャプチャー中？
	bool Component::isMouseCaptured() const
	{
		return mouseCaptureComponent.empty() ? false : (mouseCaptureComponent.top() == this);
	}

	//! マウスキャプチャー状態にする
	Component* Component::setMouseCapture(Component* component)
	{
		Component* oldMouseCapturedComponent = Component::getMouseCapture();
		mouseCaptureComponent.push(component);
		return oldMouseCapturedComponent;
	}

	//! マウスキャプチャー状態を解除する
	bool Component::releaseMouseCapture(Component* component)
	{
		if(!mouseCaptureComponent.empty() && mouseCaptureComponent.top() == component)
		{
			mouseCaptureComponent.pop();
			return true;
		}
		else
		{
			return false;
		}

	}

	//! マウスキャプチャーしているコンポーネントを取得する
	Component* Component::getMouseCapture()
	{
		return mouseCaptureComponent.empty() ? NULL : mouseCaptureComponent.top();
	}

	Component* Component::deserialize(mana_stream* stream)
	{
		Component* component = NULL;

		switch(mana_stream_get_unsigned_integer(stream))
		{
		case TYPE_COMPONENT:
			component = new Component();
			break;

		case TYPE_SCROLL_BAR:
			break;
		case TYPE_TEXT:
				/*
				 * 基本クラスをComponentでは無くBaseにする
			component = new Text();
				 */
			break;

		case TYPE_CONTAINER:
		case TYPE_STATIC_CONTAINER:
			break;

		case TYPE_VARIABLE_CONTAINER:
			component = new VariableContainer();
			break;

		case TYPE_IMAGE_BUTTON:
			component = new ImageButton();
			break;

		case TYPE_BUTTON:
			component = new Button();
			break;

		case TYPE_MESSAGE:
			component = new Message();
			break;

		case TYPE_SCENE:
			component = new Scene();
			break;
/*
		case TYPE_WINDOW:
			component = new Window();
			break;
*/
		case TYPE_MENU:
			component = new Menu();
			break;

		case TYPE_DIALOG:
			component = new Dialog();
			break;

		case TYPE_MESSAGE_WINDOW:
			component = new MessageWindow();
			break;

		case TYPE_TEXT_WINDOW:
			component = new TextWindow();
			break;

		default:
			abort(ERROR_CODE_INVALID, "unknown component type detect.");
			break;
		}

		component->onDeserialize(stream);

		return component;
	}

	void Component::allTestSerialize()
	{
#if 0
		{
			Component* component = new Component();
			component->testSerialize();
			component->release();
		}
		{
			Button* component = new Button();
			component->testSerialize();
			component->release();
		}
#if 0
		// TODO
		{
			Text* component = new Text();
			component->testSerialize();
			component->release();
		}
		{
			Container* component = new Container();
			component->testSerialize();
			component->release();
		}
#endif
		{
			Window* component = new Window();
			component->testSerialize();
			component->release();
		}
		{
			Dialog* component = new Dialog();
			component->testSerialize();
			component->release();
		}
		{
			Menu* component = new Menu();
			component->testSerialize();
			component->release();
		}
		{
			Message* component = new Message();
			component->testSerialize();
			component->release();
		}
#endif
	}

	/*!
	 * @param[in]	stream	mana_stream オブジェクト
	 */
	void Component::onSerialize(mana_stream* stream) const
	{
		mana_stream_push_unsigned_integer(stream, parent ? parent->getID() : 0);
		mana_stream_push_unsigned_char(stream, frameStyle);
#if 0
		/*
		position.serialize(stream);
		size.serialize(stream);
		offset.serialize(stream);

		scale.serialize(stream);
		animationDeltaScale.serialize(stream);
		animationTargetScale.serialize(stream);
		mana_stream_push_float(stream, scaleTime);
//		mana_stream_push_unsigned_char(stream, scaleEnable);

		color.serialize(stream);

		mana_stream_push_unsigned_char(stream, texture != NULL);
		if(texture)
			texture->serialize(stream);
*/
		animationCellStartPosition.serialize(stream);
		animationCellSize.serialize(stream);
		mana_stream_push_float(stream, animationCellTime);
		mana_stream_push_float(stream, animationCellWait);
		mana_stream_push_unsigned_short(stream, animationCellCount);
		mana_stream_push_unsigned_short(stream, animationCellMaxCount);
		mana_stream_push_short(stream, animationCellLoopCount);
		mana_stream_push_unsigned_char(stream, animationCellEnable);
		mana_stream_push_unsigned_char(stream, animationCellRunning);

		mana_stream_mark(stream);

		fadeDeltaColor.serialize(stream);
		fadeTargetColor.serialize(stream);
		mana_stream_push_float(stream, fadeColorTime);
//		mana_stream_push_unsigned_char(stream, fadeColorEnable);

		animationDeltaPosition.serialize(stream);
		animationTargetPosition.serialize(stream);
		mana_stream_push_float(stream, animationPositionTime);
//		mana_stream_push_unsigned_char(stream, animationPositionEnable);

		mana_stream_push_float(stream, jumpTime);
		mana_stream_push_float(stream, jumpAngle);
		mana_stream_push_float(stream, jumpHeight);

		mana_stream_push_float(stream, shakeTime);
		mana_stream_push_float(stream, shakeLength);
		mana_stream_push_float(stream, shakeAmplitude);

		mana_stream_push_integer(stream, data);

		mana_stream_push_unsigned_char(stream, flags);
		mana_stream_push_unsigned_char(stream, blendMode);
#endif
		mana_stream_mark(stream);
	}

	/*!
	 * @param[in]	stream	mana_stream オブジェクト
	 */
	void Component::onDeserialize(mana_stream* stream)
	{
		removeFromComponents();

		parent = reinterpret_cast<Container*>(Component::find(mana_stream_pop_unsigned_integer(stream)));
		frameStyle = mana_stream_pop_unsigned_char(stream);
#if 0
		position.deserialize(stream);
		size.deserialize(stream);
		offset.deserialize(stream);

		scale.deserialize(stream);
		animationDeltaScale.deserialize(stream);
		animationTargetScale.deserialize(stream);
		scaleTime = mana_stream_pop_float(stream);
//		scaleEnable = mana_stream_pop_unsigned_char(stream) ? true : false;

		color.deserialize(stream);

		if(mana_stream_pop_unsigned_char(stream))
		{
			texture = new Texture();
			texture->deserialize(stream);
		}

		animationCellStartPosition.deserialize(stream);
		animationCellSize.deserialize(stream);
		animationCellTime = mana_stream_pop_float(stream);
		animationCellWait = mana_stream_pop_float(stream);
		animationCellCount = mana_stream_pop_unsigned_short(stream);
		animationCellMaxCount = mana_stream_pop_unsigned_short(stream);
		animationCellLoopCount = mana_stream_pop_short(stream);
		animationCellEnable = mana_stream_pop_unsigned_char(stream) ? true : false;
		animationCellRunning = mana_stream_pop_unsigned_char(stream) ? true : false;

		mana_stream_check(stream);

		fadeDeltaColor.deserialize(stream);
		fadeTargetColor.deserialize(stream);
		fadeColorTime = mana_stream_pop_float(stream);
//		fadeColorEnable = mana_stream_pop_unsigned_char(stream) ? true : false;

		animationDeltaPosition.deserialize(stream);
		animationTargetPosition.deserialize(stream);
		animationPositionTime = mana_stream_pop_float(stream);
//		animationPositionEnable = mana_stream_pop_unsigned_char(stream);

		jumpTime = mana_stream_pop_float(stream);
		jumpAngle = mana_stream_pop_float(stream);
		jumpHeight = mana_stream_pop_float(stream);

		shakeTime = mana_stream_pop_float(stream);
		shakeLength = mana_stream_pop_float(stream);
		shakeAmplitude = mana_stream_pop_float(stream);

		data = mana_stream_pop_integer(stream);

		flags = mana_stream_pop_unsigned_char(stream);
		blendMode = mana_stream_pop_unsigned_char(stream);
#endif
		mana_stream_check(stream);

		// コンポーネントリストに追加
		components.insert(std::pair<unsigned int, Component*>(this->getID(), this));

#if 0
		// コンポーネントカウンターの調整
		if(Identification::get() <= getID())
			Identification::set(getID() + 1);
#endif
	}

	void Component::onUpdate(const UpdateInfomation& updateInfomation)
	{
		super::onUpdate(updateInfomation);
#if 0
		// セルアニメーションの更新
		if(animationCellEnable)
		{
			if(animationCellRunning)
			{
				animationCellTime += updateInfomation.deltaTime;
				while(animationCellTime >= animationCellWait)
				{
					animationCellCount++;
					if(animationCellCount >= animationCellMaxCount)
					{
						if(animationCellLoopCount >= 0)
						{
							animationCellLoopCount--;
							if(animationCellLoopCount <= 0)
							{
#if 1
								setVisible(false);
#else
								animationCellCount = animationCellMaxCount - 1;
#endif
								animationCellRunning = false;
								break;
							}
						}
						animationCellCount = 0;
					}
					animationCellTime -= animationCellTime;
				}
			}
		}
		else
		{
			// テクスチャースクロールの更新
			// (セルアニメーション中はスクロール禁止)
			if(!textureScrollSpeed.empty())
			{
				textureScrollOffset += textureScrollSpeed * updateInfomation.deltaTime;
			}
		}
#endif

		// enableによる輝度の変化
		if(getEnable())
		{
			if(enableColor >= M_PI / 2)
			{
				enableColor = M_PI / 2;
			}
			else
			{
				enableColor += M_PI / 2 * 2 * updateInfomation.deltaTime;
			}
		}
		else
		{
			if(enableColor <= 0)
			{
				enableColor = 0;
			}
			else
			{
				enableColor -= M_PI / 2 * 2 * updateInfomation.deltaTime;
			}
		}
	}

	Color Component::getDrawColor(const DrawRect& drawRect, const Color& color) const
	{
		Color baseColor = super::getDrawColor(drawRect, color);
/*
		if(getHighlightFlag() && !getOwnerDraw())
        {
			if(frameStyle & FRAME_STYLE_PUSHED)
			{
                baseColor.setMulRGB(COMPONENT_DISABLE_COLOR_LEVEL);
			}
			else
			{
				baseColor.setMulRGB(COMPONENT_DISABLE_COLOR_LEVEL + (1.0f - COMPONENT_DISABLE_COLOR_LEVEL) * sin(enableColor));
			}
        }
*/
		if(!getEnable())
		{
			baseColor.setMulRGB(COMPONENT_DISABLE_COLOR_LEVEL + (1.0f - COMPONENT_DISABLE_COLOR_LEVEL) * sin(enableColor));
		}

		return baseColor;
	}

	/*!
	 * @param[in]	drawRect	自身を描画するための環境
	 */
	bool Component::onDraw(const DrawRect& drawRect)
	{
		if(frameStyle & FRAME_STYLE_CUSTOM)
			return true;

		return super::onDraw(drawRect);
	}

	//! タッチ開始イベント
	bool Component::onTouchesBegan(const Vector2& localPosition)
	{
#if GRAPH2D_LOG_DETAIL_LEVEL >= 1
		MANA_TRACE("%s::onTouchesBegan:(%f,%f)\n", getTypeName(), localPosition.x, localPosition.y);
#endif

		// タッチ開始したローカル座標を記録
		toucheBeganPosition = localPosition;
		// ドラッギング中フラグを初期化
		dragging = false;

		return getTouchable() || isMouseCaptured();
	}

	bool Component::onTouchesMoved(const Vector2& localPosition)
	{
#if GRAPH2D_LOG_DETAIL_LEVEL >= 2
		MANA_TRACE("%s::onTouchesMoved:(%f,%f)\n", getTypeName(), localPosition.x, localPosition.y);
#endif

		// ドラッギング開始？
		if(!dragging)
		{
			if(toucheBeganPosition.squareDistance(localPosition) >= 5 * 5)
			{
				Container* component = forcusScrollableContainer(localPosition);
				if(component)
				{
					component->setMouseCapture();
					component->dragging = true;
				}
			}
		}

		return getTouchable() || isMouseCaptured();
	}

	bool Component::onTouchesEnded(const Vector2& localPosition)
	{
#if GRAPH2D_LOG_DETAIL_LEVEL >= 1
		MANA_TRACE("%s::onTouchesEnded:(%f,%f)\n", getTypeName(), localPosition.x, localPosition.y);
#endif

		if(getTouchable())
		{
			// 最後に触れたIDを記録します
			lastTouchedComponentID = getID();

			if(actionEvent)
			{
				actionEvent->onAction(this, getUserData());
			}
		}

		// マウスキャプチャー中？
		const bool captured = isMouseCaptured();

		// ドラッギング中？
		if(dragging)
		{
			releaseMouseCapture();
			dragging = false;
		}

		return getTouchable() || captured;
	}

	bool Component::onTouchesCancelled(const Vector2& localPosition)
	{
#if GRAPH2D_LOG_DETAIL_LEVEL >= 1
		MANA_TRACE("%s::onTouchesCancelled:(%f,%f)\n", getTypeName(), localPosition.x, localPosition.y);
#endif

		(void)localPosition;

		// マウスキャプチャー中？
		const bool captured = isMouseCaptured();

		// ドラッギング中？
		if(dragging)
		{
			releaseMouseCapture();
			dragging = false;
		}

		return getTouchable() || captured;
	}

	//! サイズ変更イベント
	bool Component::onSize(const Vector2& size)
	{
		return size.x >= 0 && size.y >= 0;
	}

	//! サイズ変更イベント
	void Component::onSizeChanged()
	{
	}

	bool Component::touchesBegan(const Vector2& localPosition)
	{
		if(!getEnable())
			return false;
		if(!getVisible())
			return false;
		if(!isMouseCaptured() && !isInPosition(localPosition))
			return false;
		return onTouchesBegan(localPosition);
	}

	bool Component::touchesMoved(const Vector2& localPosition)		//!< タッチ移動
	{
		if(!getEnable())
			return false;
		if(!getVisible())
			return false;
		if(!isMouseCaptured() && !isInPosition(localPosition))
			return false;
		return onTouchesMoved(localPosition);
	}

	bool Component::touchesEnded(const Vector2& localPosition)		//!< タッチ終了
	{
		if(!getEnable())
			return false;
		if(!getVisible())
			return false;
		if(!isMouseCaptured() && !isInPosition(localPosition))
			return false;
		return onTouchesEnded(localPosition);
	}

	bool Component::touchesCancelled(const Vector2& localPosition)	//!< タッチキャンセル
	{
		if(!getEnable())
			return false;
		if(!getVisible())
			return false;
		if(!isMouseCaptured() && !isInPosition(localPosition))
			return false;
		return onTouchesCancelled(localPosition);
	}

	bool Component::compare(const Component& window) const
	{
		(void)window;
/*
 if(toucheBeganPosition != other.toucheBeganPosition)
 return false;
 */
		//abort();
		return true;
	}

	void Component::panel(const Vector2& p1, const Vector2& size, const Color& color, const unsigned int frameStyle)
	{
		const Vector2 p2 = p1 + size;
		if(!Desktop::getInstance().rangeOfVisibility(p1, p2))
			return;
		const Vector2 p3(p2.x, p1.y);
		const Vector2 p4(p1.x, p2.y);

		Color baseColor(color);

		unsigned char primitiveType = 0;
		if(baseColor.a >= 1.0f)
			primitiveType |= GraphicDevice::TYPE_OPAQUE;
		if(frameStyle & FRAME_STYLE_PUSHED)
			baseColor.setMulRGB(COMPONENT_DISABLE_COLOR_LEVEL);
		if(frameStyle & FRAME_STYLE_FLAT)
		{
			GraphicDevice::setColor(baseColor);
		}
		else
		{
			primitiveType |= GraphicDevice::TYPE_COLOR;
			GraphicDevice::setColor(Color::WHITE);
		}

		GraphicDevice::begin(primitiveType, GraphicDevice::TRIANGLES, baseColor);

		if(!(frameStyle & FRAME_STYLE_FLAT))
		{
			GraphicDevice::addColor(baseColor);
			GraphicDevice::addColor(baseColor.mulRGB(0.50f));
			GraphicDevice::addColor(baseColor.mulRGB(0.25f));
			GraphicDevice::addColor(baseColor.mulRGB(0.50f));
			GraphicDevice::addColor(baseColor.mulRGB(0.25f));
			GraphicDevice::addColor(baseColor.mulRGB(0.10f));
		}

		GraphicDevice::addVertex(p1);
		GraphicDevice::addVertex(p3);
		GraphicDevice::addVertex(p4);
		GraphicDevice::addVertex(p3);
		GraphicDevice::addVertex(p4);
		GraphicDevice::addVertex(p2);

		GraphicDevice::end();

		if(!(frameStyle & FRAME_STYLE_NOLINE))
		{
			GraphicDevice::begin(primitiveType, GraphicDevice::LINE_LOOP, baseColor.mulRGB((frameStyle & FRAME_STYLE_PUSHED) ? 2.0f : 0.1f));
			GraphicDevice::addVertex(p1);
			GraphicDevice::addVertex(p3);
			GraphicDevice::addVertex(p2);
			GraphicDevice::addVertex(p4);
			GraphicDevice::end();
		}
	}

	void Component::clearAll()
	{
		// マウスキャプチャーしたコンポーネントを消去
		while(!mouseCaptureComponent.empty())
			mouseCaptureComponent.pop();

		// 最後に検索したコンポーネントを開放
		if(lastFoundComponent)
		{
			//lastFoundComponent->release();
			lastFoundComponent = NULL;
		}

		// 登録されている全てのコンポーネントを開放
		for(std::map<unsigned int, Component*>::iterator i = components.begin(); i != components.end(); i++)
		{
			//(i->second)->release();
		}
		components.clear();

#if 0
		Identification::clear();
#endif

		// componentsとの参照を切っているので、解放エラーになる
		//abort();
	}

	void Component::dumpAll()
	{
		mana_print_debug("--------------------------------------------------\n");
		for(std::map<unsigned int, Component*>::iterator i = components.begin(); i != components.end(); i++)
		{
			const unsigned int identification = i->first;
			const Component* component = i->second;
			if(component->isKindOfA(TYPE_TEXT))
			{
				const Text* text = reinterpret_cast<const Text*>(component);
				mana_print_debug("%d:%s %s\n", identification, text->getTypeName(), text->getString().c_str());
			}
			else
			{
				mana_print_debug("%d:%s\n", identification, component->getTypeName());
			}
		}
#if 0
// TODO
		for(std::map<std::string, Texture*>::iterator i = textures.begin(); i != textures.end(); i++)
		{
			const Texture* texture = i->second;
			mana_print_debug("%s(%d)\n", texture->getFileName().c_str(), texture->retainCount());
		}
#endif
	}

	// @todo:スクリプトから何度も呼び出される。可能な限り高速化してください。
	Component* Component::find(const unsigned int identification)
	{
		// 最後に検索したコンポーネントと一致した？
		if(lastFoundComponent && lastFoundComponent->getID() == identification)
		{
			return lastFoundComponent;
		}

		std::map<unsigned int, Component*>::iterator i = components.find(identification);
		if(i == components.end())
			return NULL;

		Component* foundComponent = i->second;
		lastFoundComponent = foundComponent;
		return foundComponent;
	}

	void Component::testSerialize() const
	{
		mana_stream* stream = mana_stream_create();

		onSerialize(stream);

		Component* other = Component::deserialize(stream);
		assert(compare(*other));
		//other->release();

		mana_stream_destroy(stream);
	}
}
